package com.mys.maggie.redis.api.config;

import com.mys.maggie.redis.api.spring.MagRedisService;
import com.mys.maggie.redis.api.spring.impl.MagRedisServiceImpl;
import com.mys.maggie.redis.api.util.JackSonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashMap;
import java.util.Map;


/**
 * @since 2020/8/31
 */
@Configuration
@EnableConfigurationProperties({MagRedisProperties.class})
@ComponentScan({"com.mys.maggie.redis"})
public class YcRedisAutoConfiguration {
    @Value("${spring.application.name}")
    private String application;
    
    @Autowired
    private MagRedisProperties properties;
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @Autowired
    private ConfigurableApplicationContext configurableApplicationContext;
    
    private Map<String, RedisTemplate<String, Object>> map;
    
    public Map<String, RedisTemplate<String, Object>> getMap() {
        return map;
    }
    
    @Bean
    @RefreshScope
    @ConditionalOnClass(MagRedisProperties.class)
    public YcRedisTemplateService ycRedisTemplateService() {
        properties.setApplicationName(application);
        System.out.println("加载到的redis配置 properties=" + JackSonUtil.toJSONString(properties));
        this.map = RedisDistributeService.getRedisTemplate(properties);
        
        Map<String, MagRedisService> redisServiceMap = new HashMap<>(8);
        map.forEach((key, value) -> {
            RedisTemplate<String, Object> redisTemplate = map.get(key);
            MagRedisService redisService = new MagRedisServiceImpl(redisTemplate, key);
            redisServiceMap.put(key, redisService);
            //注册 ycRedisService 注解方式
            registerMagRedisService(key, redisTemplate);
        });
        return new YcRedisTemplateService(redisServiceMap);
    }
    
    //  @SneakyThrows
    private void registerMagRedisService(String key, RedisTemplate<String, Object> redisTemplate) {
        boolean containsBean = applicationContext.containsBean(key);
        //Bean存在先销毁再创建
        if (containsBean) {
            try {
                configurableApplicationContext.getBeanFactory().destroyBean(applicationContext.getBean(key));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        DefaultListableBeanFactory capableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MagRedisServiceImpl.class);
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(MagRedisServiceImpl.class);
        ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
        constructorArgumentValues.addIndexedArgumentValue(0, redisTemplate);
        constructorArgumentValues.addIndexedArgumentValue(1, key);
        beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
        try {
            capableBeanFactory.registerBeanDefinition(key, beanDefinition);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}
